from flask import Blueprint, request, jsonify
from app.models import WorkflowInstance, WorkflowTask, WorkflowComment, User, WorkflowTemplate, FormDefinition, WorkflowHistory
from app import db
from app.routes.auth import token_required
from SpiffWorkflow.workflow import Workflow
from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer
from datetime import datetime
import json
import xml.etree.ElementTree as ET
from io import BytesIO
from lxml import etree

bp = Blueprint('workflow', __name__, url_prefix='/workflow')

# 流程模板管理API
@bp.route('/templates', methods=['GET', 'OPTIONS'])
@token_required
def get_templates(current_user):
    templates = WorkflowTemplate.query.all()
    return jsonify([{
        'id': t.id,
        'name': t.name,
        'description': t.description,
        'version': t.version,
        'status': t.status,
        'created_by': t.created_by,
        'created_at': t.created_at.isoformat(),
        'updated_at': t.updated_at.isoformat()
    } for t in templates])

@bp.route('/templates/<int:template_id>', methods=['GET', 'OPTIONS'])
@token_required
def get_template(current_user, template_id):
    template = WorkflowTemplate.query.get_or_404(template_id)
    return jsonify({
        'id': template.id,
        'name': template.name,
        'description': template.description,
        'bpmn_xml': template.bpmn_xml,
        'version': template.version,
        'status': template.status,
        'created_by': template.created_by,
        'created_at': template.created_at.isoformat(),
        'updated_at': template.updated_at.isoformat()
    })

@bp.route('/templates', methods=['POST', 'OPTIONS'])
@token_required
def create_template(current_user):
    if current_user.role != 'admin':
        return jsonify({'message': '权限不足'}), 403
        
    data = request.get_json()
    
    # 不再尝试验证BPMN XML，直接存储
    if 'name' not in data or 'bpmn_xml' not in data:
        return jsonify({'message': '缺少必要的字段：name或bpmn_xml'}), 400
    
    template = WorkflowTemplate(
        name=data['name'],
        description=data.get('description', ''),
        bpmn_xml=data['bpmn_xml'],
        status='draft',
        created_by=current_user.id
    )
    
    db.session.add(template)
    db.session.commit()
    
    return jsonify({
        'message': '流程模板创建成功',
        'template_id': template.id
    }), 201

@bp.route('/templates/<int:template_id>', methods=['PUT', 'OPTIONS'])
@token_required
def update_template(current_user, template_id):
    if current_user.role != 'admin':
        return jsonify({'message': '权限不足'}), 403
        
    template = WorkflowTemplate.query.get_or_404(template_id)
    data = request.get_json()
    
    if template.status == 'published' and 'bpmn_xml' in data:
        # 如果要修改发布状态的模板，创建新版本
        new_template = WorkflowTemplate(
            name=data.get('name', template.name),
            description=data.get('description', template.description),
            bpmn_xml=data['bpmn_xml'],
            version=template.version + 1,
            status='draft',
            created_by=current_user.id
        )
        db.session.add(new_template)
        db.session.commit()
        
        return jsonify({
            'message': '流程模板新版本创建成功',
            'template_id': new_template.id
        })
    else:
        # 修改草稿状态的模板
        if 'name' in data:
            template.name = data['name']
        if 'description' in data:
            template.description = data['description']
        if 'bpmn_xml' in data:
            template.bpmn_xml = data['bpmn_xml']
        
        db.session.commit()
        
        return jsonify({
            'message': '流程模板更新成功'
        })

@bp.route('/templates/<int:template_id>/publish', methods=['POST', 'OPTIONS'])
@token_required
def publish_template(current_user, template_id):
    if current_user.role != 'admin':
        return jsonify({'message': '权限不足'}), 403
        
    template = WorkflowTemplate.query.get_or_404(template_id)
    if template.status == 'published':
        return jsonify({'message': '模板已经是发布状态'}), 400
    
    template.status = 'published'
    db.session.commit()
    
    return jsonify({
        'message': '流程模板发布成功'
    })

@bp.route('/templates/<int:template_id>/bpmn', methods=['GET', 'OPTIONS'])
@token_required
def get_template_bpmn(current_user, template_id):
    template = WorkflowTemplate.query.get_or_404(template_id)
    return template.bpmn_xml, 200, {'Content-Type': 'application/xml'}

@bp.route('/templates/<int:template_id>', methods=['DELETE', 'OPTIONS'])
@token_required
def delete_template(current_user, template_id):
    if current_user.role != 'admin':
        return jsonify({'message': '权限不足'}), 403
        
    template = WorkflowTemplate.query.get_or_404(template_id)
    
    # 只能删除草稿状态的模板
    if template.status == 'published':
        return jsonify({'message': '已发布的模板不能删除'}), 400
    
    # 检查是否有关联的实例
    if template.instances.count() > 0:
        return jsonify({'message': '该模板有关联的流程实例，不能删除'}), 400
    
    db.session.delete(template)
    db.session.commit()
    
    return jsonify({
        'message': '流程模板删除成功'
    })

# 表单定义API
@bp.route('/forms', methods=['GET', 'OPTIONS'])
@token_required
def get_forms(current_user):
    forms = FormDefinition.query.all()
    return jsonify([{
        'id': f.id,
        'key': f.key,
        'name': f.name,
        'version': f.version,
        'created_at': f.created_at.isoformat()
    } for f in forms])

@bp.route('/forms/<int:form_id>', methods=['GET', 'OPTIONS'])
@token_required
def get_form(current_user, form_id):
    form = FormDefinition.query.get_or_404(form_id)
    return jsonify({
        'id': form.id,
        'key': form.key,
        'name': form.name,
        'schema': form.schema,
        'version': form.version,
        'created_at': form.created_at.isoformat(),
        'updated_at': form.updated_at.isoformat()
    })

@bp.route('/forms/key/<form_key>', methods=['GET', 'OPTIONS'])
@token_required
def get_form_by_key(current_user, form_key):
    form = FormDefinition.query.filter_by(key=form_key).first_or_404()
    return jsonify({
        'id': form.id,
        'key': form.key,
        'name': form.name,
        'schema': form.schema,
        'version': form.version,
        'created_at': form.created_at.isoformat(),
        'updated_at': form.updated_at.isoformat()
    })

@bp.route('/forms', methods=['POST', 'OPTIONS'])
@token_required
def create_form(current_user):
    if current_user.role != 'admin':
        return jsonify({'message': '权限不足'}), 403
        
    data = request.get_json()
    
    # 检查key是否已存在
    existing_form = FormDefinition.query.filter_by(key=data['key']).first()
    if existing_form:
        return jsonify({'message': f'表单键名 {data["key"]} 已存在'}), 400
    
    form = FormDefinition(
        key=data['key'],
        name=data['name'],
        schema=data['schema'],
        version=1
    )
    
    db.session.add(form)
    db.session.commit()
    
    return jsonify({
        'message': '表单定义创建成功',
        'form_id': form.id
    }), 201

@bp.route('/forms/<int:form_id>', methods=['PUT', 'OPTIONS'])
@token_required
def update_form(current_user, form_id):
    if current_user.role != 'admin':
        return jsonify({'message': '权限不足'}), 403
        
    form = FormDefinition.query.get_or_404(form_id)
    data = request.get_json()
    
    # 创建新版本
    if 'schema' in data:
        new_form = FormDefinition(
            key=form.key,
            name=data.get('name', form.name),
            schema=data['schema'],
            version=form.version + 1
        )
        db.session.add(new_form)
    else:
        if 'name' in data:
            form.name = data['name']
        db.session.add(form)
    
    db.session.commit()
    
    return jsonify({
        'message': '表单定义更新成功'
    })

@bp.route('/instances', methods=['GET', 'OPTIONS'])
@token_required
def list_workflows(current_user):
    if request.method == 'OPTIONS':
        return '', 200
        
    workflows = WorkflowInstance.query.filter_by(initiator_id=current_user.id).all()
    return jsonify([{
        'id': w.id,
        'type': w.workflow_type,
        'status': w.status,
        'template_id': w.template_id,
        'created_at': w.created_at.isoformat()
    } for w in workflows])

@bp.route('/instances', methods=['POST', 'OPTIONS'])
@token_required
def create_workflow(current_user):
    if request.method == 'OPTIONS':
        return '', 200
        
    data = request.get_json()
    
    if not data:
        return jsonify({'message': '请求数据不能为空'}), 400
    
    # 如果提供了模板ID，使用模板创建流程
    if 'template_id' in data:
        template = WorkflowTemplate.query.get_or_404(data['template_id'])
        if template.status != 'published':
            return jsonify({'message': '模板未发布，不能使用'}), 400
            
        # 创建流程实例
        workflow = WorkflowInstance(
            workflow_type=template.name,
            initiator_id=current_user.id,
            current_state='start',
            status='pending',
            template_id=template.id,
            variables=data.get('variables', {})
        )
        db.session.add(workflow)
        db.session.commit()
        
        # 解析BPMN并创建任务
        try:
            # 先将XML字符串解析为DOM对象
            xml_doc = etree.fromstring(template.bpmn_xml.encode('utf-8'))
            
            parser = BpmnParser()
            parser.add_bpmn_xml(xml_doc)
            
            # 获取BPMN中的流程ID
            process_id = None
            process_elements = xml_doc.findall('.//{http://www.omg.org/spec/BPMN/20100524/MODEL}process')
            if process_elements:
                process_id = process_elements[0].get('id')
            
            if not process_id:
                return jsonify({'message': 'BPMN XML中未找到有效的流程ID'}), 400
                
            # 创建工作流规范，提供流程ID
            bpmn_workflow = BpmnWorkflow(parser.get_spec(process_id))
            
            # 启动流程
            bpmn_workflow.do_engine_steps()
            
            # 创建初始任务
            initial_task = WorkflowTask(
                instance_id=workflow.id,
                task_name='提交申请',
                assignee_id=current_user.id,
                status='completed',
                task_def_key='submit',
                completed_at=datetime.utcnow()
            )
            db.session.add(initial_task)
            
            # 记录历史
            history = WorkflowHistory(
                instance_id=workflow.id,
                task_id=initial_task.id,
                activity_id='submit',
                activity_name='提交申请',
                activity_type='task',
                user_id=current_user.id,
                action='complete',
                variables=workflow.variables
            )
            db.session.add(history)
            
            # 获取待办任务
            ready_tasks = bpmn_workflow.get_ready_user_tasks()
            for task in ready_tasks:
                # 获取任务定义
                task_def = task.task_spec
                
                # 创建任务记录
                workflow_task = WorkflowTask(
                    instance_id=workflow.id,
                    task_name=task_def.name or task_def.description,
                    assignee_id=current_user.id,  # 默认分配给发起人
                    status='pending',
                    task_def_key=task_def.id
                )
                db.session.add(workflow_task)
            
            db.session.commit()
            
            return jsonify({
                'message': '流程创建成功',
                'workflow_id': workflow.id
            }), 201
            
        except Exception as e:
            db.session.rollback()
            return jsonify({'message': f'创建流程失败: {str(e)}'}), 500
    else:
        # 原有的创建流程逻辑（不使用模板）
        if 'type' not in data:
            return jsonify({'message': '未指定流程类型'}), 400
            
        workflow = WorkflowInstance(
            workflow_type=data['type'],
            initiator_id=current_user.id,
            current_state='start',
            status='pending'
        )
        db.session.add(workflow)
        db.session.commit()
        
        # 创建初始任务
        initial_task = WorkflowTask(
            instance_id=workflow.id,
            task_name='submit',
            assignee_id=current_user.id,
            status='completed'
        )
        db.session.add(initial_task)
        
        # 根据工作流类型创建后续任务
        if data['type'] == 'leave':
            dept_manager = User.query.filter_by(
                role='manager',
                department=current_user.department
            ).first()
            
            if dept_manager:
                hr_task = WorkflowTask(
                    instance_id=workflow.id,
                    task_name='dept_manager_approval',
                    assignee_id=dept_manager.id
                )
                db.session.add(hr_task)
                
                hr_staff = User.query.filter_by(role='hr').first()
                if hr_staff:
                    hr_task = WorkflowTask(
                        instance_id=workflow.id,
                        task_name='hr_approval',
                        assignee_id=hr_staff.id
                    )
                    db.session.add(hr_task)
        
        db.session.commit()
        
        return jsonify({
            'message': 'Workflow created successfully',
            'workflow_id': workflow.id
        }), 201

@bp.route('/<int:workflow_id>', methods=['GET', 'OPTIONS'])
@token_required
def get_workflow(current_user, workflow_id):
    if request.method == 'OPTIONS':
        return '', 200
        
    workflow = WorkflowInstance.query.get_or_404(workflow_id)
    if workflow.initiator_id != current_user.id and current_user.role not in ['manager', 'hr', 'admin']:
        return jsonify({'message': '无权访问此流程'}), 403
        
    tasks = WorkflowTask.query.filter_by(instance_id=workflow_id).all()
    
    # 获取发起人信息
    initiator = User.query.get(workflow.initiator_id)
    
    # 获取模板信息
    template_info = None
    if workflow.template_id:
        template = WorkflowTemplate.query.get(workflow.template_id)
        if template:
            template_info = {
                'id': template.id,
                'name': template.name,
                'description': template.description
            }
    
    return jsonify({
        'id': workflow.id,
        'type': workflow.workflow_type,
        'status': workflow.status,
        'template_id': workflow.template_id,
        'initiator': initiator.username,
        'variables': workflow.variables,
        'created_at': workflow.created_at.isoformat(),
        'updated_at': workflow.updated_at.isoformat(),
        'completed_at': workflow.completed_at.isoformat() if workflow.completed_at else None,
        'tasks': [{
            'id': t.id,
            'task_name': t.task_name,
            'status': t.status,
            'assignee': t.assignee.username,
            'task_def_key': t.task_def_key,
            'form_key': t.form_key,
            'created_at': t.created_at.isoformat(),
            'completed_at': t.completed_at.isoformat() if t.completed_at else None
        } for t in tasks]
    })

@bp.route('/<int:workflow_id>/tasks', methods=['GET', 'OPTIONS'])
@token_required
def get_workflow_tasks(current_user, workflow_id):
    if request.method == 'OPTIONS':
        return '', 200
        
    workflow = WorkflowInstance.query.get_or_404(workflow_id)
    if workflow.initiator_id != current_user.id and current_user.role not in ['manager', 'hr', 'admin']:
        return jsonify({'message': '无权访问此流程'}), 403
        
    tasks = WorkflowTask.query.filter_by(instance_id=workflow_id).all()
    return jsonify([{
        'id': t.id,
        'task_name': t.task_name,
        'status': t.status,
        'assignee': t.assignee.username,
        'task_def_key': t.task_def_key,
        'form_key': t.form_key,
        'created_at': t.created_at.isoformat(),
        'completed_at': t.completed_at.isoformat() if t.completed_at else None
    } for t in tasks])

@bp.route('/<int:workflow_id>/bpmn', methods=['GET', 'OPTIONS'])
@token_required
def get_workflow_bpmn(current_user, workflow_id):
    if request.method == 'OPTIONS':
        return '', 200
        
    workflow = WorkflowInstance.query.get_or_404(workflow_id)
    if workflow.initiator_id != current_user.id and current_user.role not in ['manager', 'hr', 'admin']:
        return jsonify({'message': '无权访问此流程'}), 403
    
    if not workflow.template_id:
        return jsonify({'message': '此流程没有关联的BPMN模板'}), 404
        
    template = WorkflowTemplate.query.get_or_404(workflow.template_id)
    
    # 解析BPMN XML
    xml_doc = etree.fromstring(template.bpmn_xml.encode('utf-8'))
    
    # 获取所有任务
    tasks = WorkflowTask.query.filter_by(instance_id=workflow_id).all()
    
    # 获取审批历史
    history_records = WorkflowHistory.query.filter_by(
        instance_id=workflow_id
    ).order_by(WorkflowHistory.timestamp).all()
    
    # 创建任务状态和历史映射
    task_status = {}
    task_assignees = {}
    task_history = {}
    
    # 任务定义键到任务记录的映射
    task_def_mapping = {}
    for task in tasks:
        if task.task_def_key:
            task_def_mapping[task.task_def_key] = task
    
    # 提取每个活动的最新状态和处理人
    for record in history_records:
        activity_id = record.activity_id
        
        # 保存活动的状态
        if record.action in ['complete', 'approve']:
            task_status[activity_id] = 'completed'
        elif record.action == 'reject':
            task_status[activity_id] = 'rejected'
        
        # 保存处理人信息
        user = User.query.get(record.user_id)
        if user:
            task_assignees[activity_id] = user.username
            
        # 保存历史记录
        if activity_id not in task_history:
            task_history[activity_id] = []
        task_history[activity_id].append({
            'action': record.action,
            'user': user.username,
            'timestamp': record.timestamp.isoformat(),
            'comment': record.comment
        })
    
    # 找到所有BPMN中的任务和用户任务元素
    ns = {'bpmn': 'http://www.omg.org/spec/BPMN/20100524/MODEL'}
    task_elements = xml_doc.findall('.//bpmn:task', ns)
    user_task_elements = xml_doc.findall('.//bpmn:userTask', ns)
    all_task_elements = task_elements + user_task_elements
    
    # 为每个BPMN任务元素添加状态和处理人信息
    for element in all_task_elements:
        task_id = element.get('id')
        
        # 检查任务ID是否存在于历史记录中
        if task_id in task_status:
            status = task_status[task_id]
            element.set('status', status)
            
            if status == 'completed':
                element.set('completed', 'true')
            elif status == 'rejected':
                element.set('rejected', 'true')
                
            # 添加处理人信息
            if task_id in task_assignees:
                element.set('assignee', task_assignees[task_id])
                
            # 添加历史记录信息
            if task_id in task_history:
                history_json = json.dumps(task_history[task_id])
                element.set('history', history_json)
        
        # 使用任务记录中的信息
        elif task_id in task_def_mapping:
            task = task_def_mapping[task_id]
            
            if task.status == 'pending':
                element.set('current', 'true')
                element.set('status', 'pending')
            
            # 添加处理人信息
            assignee = User.query.get(task.assignee_id)
            if assignee:
                element.set('assignee', assignee.username)
    
    # 标记当前活动的任务
    pending_tasks = [task for task in tasks if task.status == 'pending']
    for task in pending_tasks:
        if task.task_def_key:
            elements = xml_doc.findall(f'.//bpmn:*[@id="{task.task_def_key}"]', ns)
            for element in elements:
                element.set('current', 'true')
                element.set('status', 'pending')
                
                # 添加处理人信息
                assignee = User.query.get(task.assignee_id)
                if assignee:
                    element.set('assignee', assignee.username)
    
    # 返回修改后的BPMN XML
    return etree.tostring(xml_doc, encoding='unicode', pretty_print=True), 200, {'Content-Type': 'application/xml'}

@bp.route('/<int:workflow_id>/history', methods=['GET', 'OPTIONS'])
@token_required
def get_workflow_history(current_user, workflow_id):
    if request.method == 'OPTIONS':
        return '', 200
        
    workflow = WorkflowInstance.query.get_or_404(workflow_id)
    if workflow.initiator_id != current_user.id and current_user.role not in ['manager', 'hr', 'admin']:
        return jsonify({'message': '无权访问此流程'}), 403
    
    # 获取历史记录和评论
    history_records = WorkflowHistory.query.filter_by(instance_id=workflow_id).order_by(WorkflowHistory.timestamp).all()
    
    # 合并历史记录和评论
    combined_history = []
    for record in history_records:
        user = User.query.get(record.user_id)
        combined_history.append({
            'id': record.id,
            'activity_id': record.activity_id,
            'activity_name': record.activity_name,
            'activity_type': record.activity_type,
            'user': user.username,
            'action': record.action,
            'comment': record.comment,
            'timestamp': record.timestamp.isoformat()
        })
    
    return jsonify(combined_history)

@bp.route('/<int:workflow_id>/approve', methods=['POST', 'OPTIONS'])
@token_required
def approve_workflow(current_user, workflow_id):
    if request.method == 'OPTIONS':
        return '', 200
        
    task = WorkflowTask.query.filter_by(
        instance_id=workflow_id,
        assignee_id=current_user.id,
        status='pending'
    ).first_or_404()
    
    data = request.get_json() or {}
    
    task.status = 'completed'
    task.completed_at = datetime.utcnow()
    
    # 记录历史
    history = WorkflowHistory(
        instance_id=workflow_id,
        task_id=task.id,
        activity_id=task.task_def_key or task.task_name,
        activity_name=task.task_name,
        activity_type='task',
        user_id=current_user.id,
        action='approve',
        comment=data.get('comment')
    )
    db.session.add(history)
    
    # 添加评论（如果有）
    if data.get('comment'):
        comment = WorkflowComment(
            task_id=task.id,
            user_id=current_user.id,
            comment=data['comment']
        )
        db.session.add(comment)
    
    # 检查是否所有任务都已完成
    workflow = WorkflowInstance.query.get(workflow_id)
    if all(t.status == 'completed' for t in workflow.tasks):
        workflow.status = 'completed'
        workflow.completed_at = datetime.utcnow()
    
    db.session.commit()
    return jsonify({'message': '流程审批成功'})

@bp.route('/<int:workflow_id>/reject', methods=['POST', 'OPTIONS'])
@token_required
def reject_workflow(current_user, workflow_id):
    if request.method == 'OPTIONS':
        return '', 200
        
    task = WorkflowTask.query.filter_by(
        instance_id=workflow_id,
        assignee_id=current_user.id,
        status='pending'
    ).first_or_404()
    
    data = request.get_json() or {}
    
    task.status = 'rejected'
    task.completed_at = datetime.utcnow()
    
    # 记录历史
    history = WorkflowHistory(
        instance_id=workflow_id,
        task_id=task.id,
        activity_id=task.task_def_key or task.task_name,
        activity_name=task.task_name,
        activity_type='task',
        user_id=current_user.id,
        action='reject',
        comment=data.get('comment')
    )
    db.session.add(history)
    
    # 添加评论（如果有）
    if data.get('comment'):
        comment = WorkflowComment(
            task_id=task.id,
            user_id=current_user.id,
            comment=data['comment']
        )
        db.session.add(comment)
    
    workflow = WorkflowInstance.query.get(workflow_id)
    workflow.status = 'rejected'
    
    db.session.commit()
    return jsonify({'message': '流程已拒绝'})

@bp.route('/tasks', methods=['GET', 'OPTIONS'])
@token_required
def get_tasks(current_user):
    if request.method == 'OPTIONS':
        return '', 200
        
    tasks = WorkflowTask.query.filter_by(
        assignee_id=current_user.id,
        status='pending'
    ).all()
    
    result = []
    for task in tasks:
        workflow = WorkflowInstance.query.get(task.instance_id)
        initiator = User.query.get(workflow.initiator_id)
        
        # 获取表单定义
        form_data = None
        if task.form_key:
            form = FormDefinition.query.filter_by(key=task.form_key).first()
            if form:
                form_data = {
                    'id': form.id,
                    'key': form.key,
                    'name': form.name,
                    'schema': form.schema
                }
        
        result.append({
            'id': task.id,
            'workflow_id': task.instance_id,
            'workflow_type': workflow.workflow_type,
            'task_name': task.task_name,
            'task_def_key': task.task_def_key,
            'status': task.status,
            'form': form_data,
            'initiator': {
                'id': initiator.id,
                'username': initiator.username,
                'department': initiator.department
            },
            'variables': workflow.variables,
            'created_at': task.created_at.isoformat()
        })
    
    return jsonify(result) 